package com.softer.chengxin.common.util;

import com.softer.chengxin.modify.dao.BaseModifyDetailDao;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Gong Zhiyang
 * @date 2019/9/11
 */
@Slf4j
@Component
public class ModifyUtil<T> {
    @Autowired
    private BaseModifyDetailDao baseModifyDetailDao;

    /**
     * 获取变更字段合并到目标实体
     *
     * @param id         业务ID
     * @param type       变更类型（1企业基本信息变更，0项目基本信息变更)
     * @param targetBean 实体类型
     * @return 实体
     */
    public T getCompleteEntity(int id, T targetBean, String type) {
        Map<String, Object> map = listToMap(id, type);
        return mapCombineEntity(map, targetBean);
    }

    /**
     * List<Map>转map
     *
     * @param id   业务ID
     * @param type 变更类型（1企业基本信息变更，0项目基本信息变更)
     * @return map
     */
    private Map<String, Object> listToMap(int id, String type) {
        List<Map<String, Object>> list = baseModifyDetailDao.getDetailListByBusinessId(id, type);
        Map<String, Object> resultMap = new HashMap<>(8);
        for (Map<String, Object> map : list) {
            String mapKey = String.valueOf(map.get("param"));
            String mapValue = null;
            if (!"".equals(String.valueOf(map.get("value")))) {
                mapValue = String.valueOf(map.get("value"));
            }
            resultMap.put(mapKey, mapValue);
        }
        for (Map.Entry<String, Object> entry : resultMap.entrySet()) {
            String key = entry.getKey();
            log.info("{}:{}", key, resultMap.get(key));
        }
        return resultMap;
    }

    /**
     * map合并到实体类中
     *
     * @param map        变更map
     * @param targetBean 实体
     * @return 实体
     */
    private T mapCombineEntity(Map<String, Object> map, T targetBean) {
        Class<?> clazz = targetBean.getClass();
        if (map != null && map.size() > 0) {
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                //属性名
                String propertyName = entry.getKey();
                Object value = entry.getValue();
                String setMethodName = "set"
                        + propertyName.substring(0, 1).toUpperCase()
                        + propertyName.substring(1);
                try {
                    Field field = getClassField(clazz, propertyName);
                    if (field == null) {
                        continue;
                    }
                    Class<?> fieldTypeClass = field.getType();
                    value = convertValType(value, fieldTypeClass);
                    clazz.getMethod(setMethodName, field.getType()).invoke(targetBean, value);
                } catch (Exception e) {
                    log.error("实体转化异常:", e.getMessage());
                }
            }
        }
        return targetBean;
    }

    /**
     * 获取指定字段名称查找在class中的对应的Field对象(包括查找父类)
     *
     * @param clazz     指定的class
     * @param fieldName 字段名称
     * @return Field对象
     */
    private static Field getClassField(Class<?> clazz, String fieldName) {
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.getName().equals(fieldName)) {
                return field;
            }
        }
        Class<?> superClass = clazz.getSuperclass();
        if (superClass != null) {
            return getClassField(superClass, fieldName);
        }
        return null;
    }

    /**
     * 将Object类型的值，转换成bean对象属性里对应的类型值
     *
     * @param value          Object对象值
     * @param fieldTypeClass 属性的类型
     * @return 转换后的值
     */
    private static Object convertValType(Object value, Class<?> fieldTypeClass) {
        Object retVal;
        if (Long.class.isAssignableFrom(fieldTypeClass)
                || long.class.isAssignableFrom(fieldTypeClass)) {
            retVal = Long.parseLong(value.toString());
        } else if (Integer.class.isAssignableFrom(fieldTypeClass)
                || int.class.isAssignableFrom(fieldTypeClass)) {
            retVal = Integer.parseInt(value.toString());
        } else if (Float.class.isAssignableFrom(fieldTypeClass)
                || float.class.isAssignableFrom(fieldTypeClass)) {
            retVal = Float.parseFloat(value.toString());
        } else if (Double.class.isAssignableFrom(fieldTypeClass)
                || double.class.isAssignableFrom(fieldTypeClass)) {
            retVal = Double.parseDouble(value.toString());
        } else if (BigDecimal.class.isAssignableFrom(fieldTypeClass)) {
            retVal = BigDecimal.valueOf(Double.parseDouble(value.toString()));
        } else if (Date.class.isAssignableFrom(fieldTypeClass)) {
            retVal = new Date();
        } else {
            retVal = value;
        }
        return retVal;
    }

}
